<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf8">
<meta name="Microsoft Theme" content="none">
<title>实验中常见调试错误</title>
</head>
<body background="../index.files/back_bluh.jpg" style="background-attachment: fixed">

<font size="5" color="#3366FF"><b>实验中常见调试错误</b></font>
<pre>
			<a href="#1">语法错误</a>		<a href="#2">逻辑错误</a>		<a href="#3" >编写汇编语言的忠告</a>			</pre>
<pre>
一、<a name="1" >语</a>法错误及其分析：
	</pre>
<pre>1. 标号重复：</pre>
<pre>	1)复制、粘贴程序时忘记修改标号，造成出现多个相同的标号</pre>
<pre>	2)在设计包含多个子程序的程序，不同子程序中存在相同的标号（常见的有循环入口标号）。这种情况可以通过把不同子程序的标号子程序名关联的方法解决
            </pre>
<pre>2．标点符号以全角方式输入：</pre>
<pre>	汇编程序要求标点符号为半角方式，否则汇编失败。常出现的错误标点有：</pre>
<pre>	1）注释标记符 ; </pre>
<pre>	2）地址标号标记符 :</pre>
<pre>	3)字符串标记 &quot;&quot;  和 ''       
            </pre>
<pre>3．在编辑asm文件时，其中的十六进制数据以字母开头：</pre>
<pre>	根据要求应该在a～f前加数字0，例如：ffffh应该写成0ffffh； abcdh应该写成0abcdh</pre>
<pre>4．字母和数字搞混：</pre>
<pre>	1）字母o和数字0</pre>
<pre>	2）字母I,l和数字1</pre>
<pre>5．在地址标号后边遗漏&quot;：&quot;</pre>
<pre>6．标号使用了特殊字符：</pre>
<pre>	标号不能用指令助记符、伪指令、特殊功能寄存器名和8051在指令系统中用的“#”、“@”等。</pre>
<pre>7．跳转指令跳转地址超过规定范围：</pre>
<pre>	注意jmp，jb等跳转指令的跳转范围。</pre>
<pre>8.创造发明不存在的汇编语言指令：</pre>
<pre>	在编写程序程序的过程中可不欢迎这种创新，这种指令汇编程序不支持，芯片也不认可。</pre>
<pre>　</pre>
<pre>小结：</pre>
<pre>1，出错原因：以上在大多数情况是因为自己粗心大意造成的，不过很容易在调试的过程中发现它们。</pre>
<pre>2，错误类型：语法错误，这种错误都是在编译时出现，在编译的过程中编译器会提示（当然不要形成依赖性，我们最好是在编辑源程序的过程中，自己注意，否则调试</pre>
<pre>起来也是很伤脑筋的）。</pre>
<pre>3，解决办法：多编写程序，多积累，并且在编辑源程序的时候养成一些良好的习惯：例如在中英文切换的时候提高警惕，避免弄混标点符号。</pre>
<pre> 
</pre>
<pre>二、<a name="2">逻</a>辑错误：</pre>
<pre>1．寄存器冲突：</pre>
<pre>
	我们知道，寄存器的个数是非常有限的，而有些时候，我们需要处理的变量个数却非常的多，难免造成“寄存器忙不过来”的情况，在没有注意的情况下，有</pre>
<pre>“用一个寄存器在同一个时刻存放几个变量”，这样造成的影响是：实际上我们在寄存器中只保存了一个变量，即我们最后一次放进去的那个，而我们原来放入的全部丢</pre>
<pre>失拉。你完全可以想象，这种情况的恶劣。</pre>
<pre>	面对这样的苦恼，我们该如何办呢？</pre>
<pre>	内存。</pre>
<pre>	我们用寄存器经常进行的操作的数据的传递，而数据的传递还有约定存储单元法，堆栈法等，而后面两种方法都是对利用内存实现，所以为了缓解寄存器的紧</pre>
<pre>张局面，我们要在适当的时候使用后面的方法。虽然操作起来没有前者方便，但是在寄存器产生冲突的情况，后者未免不是很好的解决办法。</pre>
<pre>	另外特别提到段寄存器冲突时的一种情况，实例见实验五的第五题：题目中有四个段，而可用的代码段寄存器cs，余下的只有栈段寄存器ss，数据段寄存器ds以及</pre>
<pre>附加段寄存器es，注意到这里三个数据段中的数据都是字节型，显然用栈操作不易实现，那么只好用约定存储器和约定寄存器的方法实现，但是现在只有ds和es可用，现在还</pre>
<pre>差一个段寄存器，怎么办？共用一个段寄存器。问题不是马上就解决了，我们还得注意到“每个段占用的实际空间是16字节”，所以下一个段的偏移地址并不是所有情况下都</pre>
<pre>是上一个数据段的偏移地址加上它所定义的数据段的长度，仅仅当其中定义的数据段长度大于16个字节才是。</pre>
<pre>2.push与pop语句不匹配：</pre>
<pre>	在子程序中，或者在缓解寄存器冲突的情况下，我们经常使用堆栈法，也就得用到这两个“夫妻指令”（我自己命名的，表示它们经常是在一起的）。</pre>
<pre>正因为如此，它们之间常因为“红杏出墙”或者“夫君有外情”，或者“不专一”等出现问题。例如：</pre>
<pre>	1）现有 push ax ，我们的目的是为了缓解寄存器的冲突，之后我们要把刚压栈的数据恢复到ax，可是，与前者对应的位置上我们却使用了pop bx</pre>
<pre>	2）又如：在子程序的保护相关寄存器的工作时，前面出现了8个push操作，可是后面只有7pop操作，这样当执行ret指令恢复cs和ip的时候，就会出现错误，</pre>
<pre>从而发生不可预测的结果。</pre>
<pre>	3）再一个比较常见的是：不小心把一个push语句放入了循环语句，与之对应的pop语句却在循环语句之外，这样造成的不匹配是特别难堪的</pre>
<pre>	另外push和pop语句都只对字进行操作，如果对al等字节型寄存器进行操作，属于语法错误，编译器会提示；但是，如果我们对数据段中定义的字节型数据进行操</pre>
<pre>作，可能就会造成数据覆盖等现象，发生灾难性的结果。这里具体见实验五的第5题，请思考，那里是否可以用栈进行操作？  
</pre>
<pre>3）内存空间的代码覆盖	</pre>
<pre>	内存空间也会存在冲突，因为毕竟内存空间也是有限的，我们经常有意无意的在某一次操作的前后对同一段内存空间进行写操作。我们仅举课程设计二中的最后面强调的注意内容，请仔细</pre>
<pre>查看。其实这类情况造成的结果也是非常可怕的。而且很难发现。根据经验，当我们在跟踪调试程序的过程时，程序突然执行到未知的代码，很有可能是是因为内存空间的代</pre>
<pre>码覆盖（当然也有可能是某些涉及修改cs：ip的指令处的操作不符合要求）。</pre>
<pre>4）没有指明程序的入口</pre>
<pre>	这种情况也会经常出现，从而可能导致cs：ip指向了数据段，或者指向其他某个未知的内存空间。这里我们要切记下面的操作的重要性：</pre>
<pre>	code segment</pre>
<pre>	start:</pre>
<pre>		……</pre>
<pre>	code ends</pre>
<pre>	end start </pre>
<pre>         这样我们可以通过start指明程序的入口，虽然在某些情况无须指明程序的入口，但是这样可以确保万无一失，具体见实验五中的问题四。</pre>
<pre>　</pre>
<pre>小结：</pre>
<pre>1，出错原因：</pre>
<pre>	a.算法的不健壮性：在设计算法的时候，没有考虑到所有可能出现的情况，从而造成某些不可预料的结果</pre>
<pre>	b.在编辑源代码的过程中不是完全体现算法的思想，甚至可能出现代码的误编辑从而歪曲原来的算法，得不到正确的结果</pre>
<pre>2，错误类型：逻辑错误，编译器无法进行提示，必须有我们自己去查找。通常的查找顺序是：</pre>
<pre>	a,根据经验快速判断并找到可能出错的地方</pre>
<pre>	b,单步跟踪调试程序是否按照我们的算法思想执行</pre>
<pre>	c,如果发现是算法出错，那么回到算法本身，研究算法</pre>
<pre>3，解决办法：</pre>
<pre>	a,养成一个良好的编程过程：数学建模――算法设计――编程调试；我们往往喜欢拿到题目就往电脑前做，往电脑里输，可是我们连最根本的思路都没有，怎么谈</pre>
<pre>顺利的完成某个题目呢？这样往往是得不偿失。有时，我们在先设计好算法之后再编写源代码往往可以来得更快，而且很少出现错误。这就好比写作文，先写个提纲，再写具</pre>
<pre>体内容往往更流畅。</pre>
<pre>	b,养成良好的编辑习惯：在编写源程序的过程，往往由于我们的本能造成好多疏忽，但是如果养成了一些良好的习惯，就可以把这个疏忽降低到最低程度。这种两</pre>
<pre>好的习惯有很多，比如代码格式，标号等的命名知意原则，一些必要的注释等等，这些就是所谓的编程风格，自己在平时要不断的练习和积累。</pre>
<pre>	c,单步跟踪：这是对我们的“疏忽”的一针药剂，当然这只是最后一步拉，所谓“绝境”，你肯定不希望自己落入“绝境”吧，所以之前最好是少些“疏忽”。</pre>
<pre>对于汇编语言，可以结合debug中的一些常用的指令t,r,d,u,a,e等进行单步调试。这是“绝境”，所以为了防止有一天我们被迫落入“绝境”，还是得学会应对的。</pre>
<pre>　</pre>
<pre>三，<a name="3"> 编</a>写汇编语言的忠告
</pre>
<pre>	1）要养成良好的程序书写习惯，比如标号对齐、参数对齐、注释对齐，这样看起来赏心悦目，也不容易出错。</pre>
<pre>	2）标号最好采用有意义的英文，这样比较直观，</pre>
<pre>	3）注释尽量详细准确，便于以后读懂，而且有利于其它程序中作为子程序模块的调用。</pre>
<pre>	4）还有要注意典型程序模块的积累，再复杂的程序也是由一个个小程序模块组成的，在初学阶段可以对典型程序比如：延时子程序、查表子程序、按键消停子程序</pre>
<pre>等编写实践一次。

</pre>
<div align="left">
  <PRE><center><b>
	<a href="../"><font face="华文行楷" size="5" color="#3333FF">返回目录</font></a></b></center></pre>
</div>
